package com.code.aicodemother.service.impl;

import com.code.aicodemother.service.CaptchaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 验证码服务实现类
 *
 * @author ys
 */
@Service
@Slf4j
public class CaptchaServiceImpl implements CaptchaService {

    /**
     * 验证码存储 (生产环境建议使用Redis)
     */
    private final ConcurrentHashMap<String, CaptchaInfo> captchaStore = new ConcurrentHashMap<>();

    /**
     * 定时清理过期验证码
     */
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    /**
     * 验证码字符集
     */
    private static final String CAPTCHA_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz";

    /**
     * 验证码长度
     */
    private static final int CAPTCHA_LENGTH = 4;

    /**
     * 验证码图片宽度
     */
    private static final int IMAGE_WIDTH = 120;

    /**
     * 验证码图片高度
     */
    private static final int IMAGE_HEIGHT = 40;

    /**
     * 验证码有效期（分钟）
     */
    private static final int CAPTCHA_EXPIRE_MINUTES = 5;

    public CaptchaServiceImpl() {
        // 启动定时清理任务，每分钟清理一次过期验证码
        scheduler.scheduleAtFixedRate(this::cleanExpiredCaptcha, 1, 1, TimeUnit.MINUTES);
    }

    @Override
    public CaptchaResult generateCaptcha() {
        // 生成验证码文本
        String captchaText = generateCaptchaText();
        
        // 生成唯一key
        String captchaKey = generateCaptchaKey();
        
        // 生成验证码图片
        String captchaImage = generateCaptchaImage(captchaText);
        
        // 存储验证码信息
        long expireTime = System.currentTimeMillis() + CAPTCHA_EXPIRE_MINUTES * 60 * 1000;
        captchaStore.put(captchaKey, new CaptchaInfo(captchaText, expireTime));
        
        log.info("生成验证码: key={}, text={}", captchaKey, captchaText);
        
        return new CaptchaResult(captchaKey, captchaImage);
    }

    @Override
    public boolean verifyCaptcha(String captchaKey, String captchaCode) {
        if (captchaKey == null || captchaCode == null) {
            return false;
        }
        
        CaptchaInfo captchaInfo = captchaStore.get(captchaKey);
        if (captchaInfo == null) {
            log.warn("验证码不存在: key={}", captchaKey);
            return false;
        }
        
        // 先检查是否过期
        if (System.currentTimeMillis() > captchaInfo.getExpireTime()) {
            log.warn("验证码已过期: key={}", captchaKey);
            captchaStore.remove(captchaKey); // 移除过期验证码
            return false;
        }
        
        // 验证码使用后立即删除（无论验证成功失败）
        captchaStore.remove(captchaKey);
        
        // 验证码比较（转小写后比较）
        String inputCode = captchaCode.trim().toLowerCase();
        boolean isValid = captchaInfo.getText().equals(inputCode);
        log.info("验证码校验: key={}, expected={}, actual={}, inputLower={}, valid={}", 
                captchaKey, captchaInfo.getText(), captchaCode, inputCode, isValid);
        
        return isValid;
    }

    /**
     * 生成验证码文本
     */
    private String generateCaptchaText() {
        Random random = new Random();
        StringBuilder captcha = new StringBuilder();
        for (int i = 0; i < CAPTCHA_LENGTH; i++) {
            captcha.append(CAPTCHA_CHARS.charAt(random.nextInt(CAPTCHA_CHARS.length())));
        }
        return captcha.toString();
    }

    /**
     * 生成验证码key
     */
    private String generateCaptchaKey() {
        return "captcha_" + System.currentTimeMillis() + "_" + new Random().nextInt(10000);
    }

    /**
     * 生成验证码图片
     */
    private String generateCaptchaImage(String captchaText) {
        BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();
        
        // 设置抗锯齿
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        // 填充背景
        g2d.setColor(new Color(240, 248, 255));
        g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
        
        // 绘制干扰线
        Random random = new Random();
        g2d.setColor(new Color(200, 200, 200));
        for (int i = 0; i < 5; i++) {
            int x1 = random.nextInt(IMAGE_WIDTH);
            int y1 = random.nextInt(IMAGE_HEIGHT);
            int x2 = random.nextInt(IMAGE_WIDTH);
            int y2 = random.nextInt(IMAGE_HEIGHT);
            g2d.drawLine(x1, y1, x2, y2);
        }
        
        // 绘制验证码文字
        Font font = new Font("Arial", Font.BOLD, 24);
        g2d.setFont(font);
        
        FontMetrics fontMetrics = g2d.getFontMetrics();
        int totalWidth = fontMetrics.stringWidth(captchaText);
        int startX = (IMAGE_WIDTH - totalWidth) / 2;
        int startY = (IMAGE_HEIGHT + fontMetrics.getHeight()) / 2 - fontMetrics.getDescent();
        
        for (int i = 0; i < captchaText.length(); i++) {
            char ch = captchaText.charAt(i);
            
            // 随机颜色
            g2d.setColor(new Color(random.nextInt(150), random.nextInt(150), random.nextInt(150)));
            
            // 计算字符位置
            int charWidth = fontMetrics.charWidth(ch);
            int x = startX + i * (totalWidth / captchaText.length());
            int y = startY + random.nextInt(6) - 3; // 随机垂直偏移
            
            // 绘制字符
            g2d.drawString(String.valueOf(ch), x, y);
        }
        
        // 绘制干扰点
        for (int i = 0; i < 50; i++) {
            int x = random.nextInt(IMAGE_WIDTH);
            int y = random.nextInt(IMAGE_HEIGHT);
            g2d.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
            g2d.fillOval(x, y, 1, 1);
        }
        
        g2d.dispose();
        
        // 转换为Base64
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);
            byte[] imageBytes = baos.toByteArray();
            return "data:image/png;base64," + Base64.getEncoder().encodeToString(imageBytes);
        } catch (IOException e) {
            log.error("生成验证码图片失败", e);
            throw new RuntimeException("生成验证码图片失败", e);
        }
    }

    /**
     * 清理过期验证码
     */
    private void cleanExpiredCaptcha() {
        long currentTime = System.currentTimeMillis();
        captchaStore.entrySet().removeIf(entry -> {
            boolean expired = currentTime > entry.getValue().getExpireTime();
            if (expired) {
                log.debug("清理过期验证码: key={}", entry.getKey());
            }
            return expired;
        });
    }

    /**
     * 验证码信息
     */
    private static class CaptchaInfo {
        private final String text;
        private final long expireTime;

        public CaptchaInfo(String text, long expireTime) {
            this.text = text;
            this.expireTime = expireTime;
        }

        public String getText() {
            return text;
        }

        public long getExpireTime() {
            return expireTime;
        }
    }
}
